package com.sailing.xjpb.common.encrypt;

import com.sailing.xjpb.common.exception.ConvertException;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * AES加密|解密
 *
 * @author YW
 */
public final class Aes {

    private Aes() {

    }

    /**
     * 生成的key的范围
     */
    private static final String KEY_CHARS = "abcdefghijklmnopqrstuvwxyz1234567890+-/ABCDEFGHIJKLMNOPQRSTUVWXYZ=";
    /**
     * 随机数生成器
     */
    private static final SecureRandom random = new SecureRandom();
    /**
     * 加密算法
     */
    private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";

    /**
     * @param key     加密key--16位
     * @param content 加密内容
     */
    public static String encode(String key, String content) {
        Cipher cipher = getCipher(key, Cipher.ENCRYPT_MODE);
        try {
            return Base64.encodeBase64String(cipher.doFinal(content.getBytes(StandardCharsets.UTF_8))).replace("\r\n"
                    , "");
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            throw new ConvertException("加密过程出现错误", e);
        }
    }

    /**
     * @param key     加密key--16位
     * @param content 加密内容
     */
    public static String decode(String key, String content) {
        Cipher cipher = getCipher(key, Cipher.DECRYPT_MODE);
        try {
            return new String(cipher.doFinal(Base64.decodeBase64(content)), StandardCharsets.UTF_8);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            throw new ConvertException("解密过程出现错误", e);
        }
    }

    /**
     * 获取加密算法
     *
     * @param keyStr     加密key
     * @param cipherMode 加密/解密
     */
    private static Cipher getCipher(String keyStr, int cipherMode) {
        try {
            byte[] bytesIV = new byte[16];
            random.nextBytes(bytesIV);
            bytesIV = keyStr.getBytes();
            IvParameterSpec zeroIv = new IvParameterSpec(bytesIV);
            SecretKeySpec key = new SecretKeySpec(keyStr.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(cipherMode, key, zeroIv);
            return cipher;
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
                | InvalidAlgorithmParameterException e) {
            throw new ConvertException("初始化AES加密算法出错", e);
        }
    }

    /**
     * 生成16位key
     */
    public static String randomKey() {
        StringBuilder keyBuilder = new StringBuilder();
        int len = 16;
        for (int i = 0; i < len; i++) {
            keyBuilder.append(KEY_CHARS.charAt(random.nextInt(KEY_CHARS.length())));
        }
        return keyBuilder.toString();
    }
}
